package client.presenter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import client.model.Model;
import client.model.maze.GameMazeModel;
import client.model.maze.generator.HuntAndKillMazeGenerator;
import client.model.maze.generator.MazeGenerator;
import client.model.maze.generator.PrimMazeGenerator;
import client.model.maze.generator.RecursiveBacktrackerMazeGenerator;
import client.model.twoThousandFortyEight.Game2048Model;
import client.view.Board;
import client.view.View;
import client.view.maze.GameMazeView;
import client.view.twothousandfortyeight.Game2048View;
import common.WrapperTask;
import common.XmlSerializer;

public class GameMenu implements Runnable {
	private Display display;
	private Shell shell;
	private Model model;
	private View view;
	private Presenter presenter;
	private ClientSettings settings;
	
	private Board board;
	private Label scoreLabel;
	private Button undoButton;
	private Button restartButton;
	private Label separatorLabel;
	private Label hintImageLabel;
	private Image hintImage;
	private Label stepsToSolveLabel;
	private Text stepsToSolveText;
	private Button hintButton;
	private Button solveButton;
	
	private int autoSolveSpeed;
	
	public void run() {
		try {
			initComponents();
			
			settings = (ClientSettings)XmlSerializer.loadSettings(".\\settings\\client.config", new ClientSettings());
			
			ServerHandler.serverIP = settings.getServerIP();
			ServerHandler.connectionPort = settings.getConnectionPort();
			ServerHandler.socketTimeout = settings.getSocketTimeout();
			
			autoSolveSpeed = settings.getAutoSolveNormalSpeed();

			shell.open();
		}
		catch (IOException e) {
			MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
			messageBox.setText("Initialization Error");
			messageBox.setMessage("Cannot find the \\settings\\client.config file.");
			messageBox.open();
			
			shell.close();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			while (!shell.isDisposed()) {
				if (!display.readAndDispatch()) {
					display.sleep();
				}
			}
			
			if (timer != null) {
				timer.cancel();
				timer.purge();
			}
			
			display.dispose();
		}
	}
	
	private void initComponents() {
		display = new Display();
		shell = new Shell(display);
		shell.setLayout(new GridLayout(4, false));
		shell.setSize(500, 487);
		shell.setText("Amazing Maze & 2048 Game!");
		
		initMenuItems();
		initFormItems();
	}
	
	private void initMenuItems() {
		//Menu
		Menu menu = new Menu(shell, SWT.BAR);
		shell.setMenuBar(menu);
		
		//File menu
		Menu fileMenu = new Menu(shell, SWT.DROP_DOWN);
		MenuItem cascadeFileMenu = new MenuItem(menu, SWT.CASCADE);
		cascadeFileMenu.setText("&File");
		cascadeFileMenu.setMenu(fileMenu);
		
		//New 2048 Game menu item
		MenuItem new2048Game = new MenuItem(fileMenu, SWT.PUSH);
		new2048Game.setText("&New 2048 Game");
		new2048Game.addSelectionListener(newGame2048);
		
		//New Maze Game menu item
		MenuItem newMazeGame = new MenuItem(fileMenu, SWT.CASCADE);
		newMazeGame.setText("&New Maze Game");
		
		Menu mazeSubMenu = new Menu(menu);
		newMazeGame.setMenu(mazeSubMenu);
		
		//Starter Maze Game sub-menu item 
		MenuItem starterMaze = new MenuItem(mazeSubMenu, SWT.PUSH);
		starterMaze.setText("&Starter      - With diagonal movement");
		starterMaze.addSelectionListener(starterGameMaze);
				
		//Easy Maze Game sub-menu item 
		MenuItem easyMaze = new MenuItem(mazeSubMenu, SWT.PUSH);
		easyMaze.setText("&Easy          - Prim algorithm");
		easyMaze.addSelectionListener(easyGameMaze);
		
		//Medium Maze Game sub-menu item
		MenuItem mediumMaze = new MenuItem(mazeSubMenu, SWT.PUSH);
		mediumMaze.setText("&Medium  - Hunt-And-Kill algorithm");
		mediumMaze.addSelectionListener(mediumGameMaze);
		
		//Hard Maze Game sub-menu item
		MenuItem hardMaze = new MenuItem(mazeSubMenu, SWT.PUSH);
		hardMaze.setText("&Hard         - Backtracker algorithm");
		hardMaze.addSelectionListener(hardGameMaze);
		
		//Separator
		new MenuItem(fileMenu, SWT.SEPARATOR);
		
		//Save Game menu item
		MenuItem saveItem = new MenuItem(fileMenu, SWT.PUSH);
		saveItem.setText("&Save Game");
		saveItem.addSelectionListener(saveSelected);
		
		//Load Game menu item
		MenuItem loadItem = new MenuItem(fileMenu, SWT.PUSH);
		loadItem.setText("&Load Game");
		loadItem.addSelectionListener(loadSelected);

		//Separator
		new MenuItem(fileMenu, SWT.SEPARATOR);
				
		//Exit menu item
		MenuItem exitItem = new MenuItem(fileMenu, SWT.PUSH);
		exitItem.setText("&Exit");
		exitItem.addSelectionListener(exitSelected);

		//Edit menu
		Menu editMenu = new Menu(shell, SWT.DROP_DOWN);
		MenuItem cascadeEditMenu = new MenuItem(menu, SWT.CASCADE);
		cascadeEditMenu.setText("&Edit");	
		cascadeEditMenu.setMenu(editMenu);
		
		//Undo menu item
		MenuItem undoItem = new MenuItem(editMenu, SWT.PUSH);
		undoItem.setText("&Undo");
		undoItem.addSelectionListener(undoSelected);
		
		//Restart menu item
		MenuItem restartItem = new MenuItem(editMenu, SWT.PUSH);
		restartItem.setText("&Restart");
		restartItem.addSelectionListener(restartSelected);
		
		//Solve Speed menu
		Menu solveSpeedMenu = new Menu(shell, SWT.DROP_DOWN);
		MenuItem cascadeSolveSpeedMenu = new MenuItem(menu, SWT.CASCADE);
		cascadeSolveSpeedMenu.setText("&Solve Speed");	
		cascadeSolveSpeedMenu.setMenu(solveSpeedMenu);
		
		//Slow speed menu item
		MenuItem slowItem = new MenuItem(solveSpeedMenu, SWT.PUSH);
		slowItem.setText("&Slow");
		slowItem.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				autoSolveSpeed = settings.getAutoSolveSlowSpeed();
			}
			
			@Override
			public void widgetDefaultSelected(SelectionEvent arg0) {
			}
		});
		
		//Normal speed menu item
		MenuItem normalItem = new MenuItem(solveSpeedMenu, SWT.PUSH);
		normalItem.setText("&Normal");
		normalItem.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				autoSolveSpeed = settings.getAutoSolveNormalSpeed();
			}
			
			@Override
			public void widgetDefaultSelected(SelectionEvent arg0) {
			}
		});
		
		//Fast speed menu item
		MenuItem fastItem = new MenuItem(solveSpeedMenu, SWT.PUSH);
		fastItem.setText("&Fast");
		fastItem.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				autoSolveSpeed = settings.getAutoSolveFastSpeed();
			}
			
			@Override
			public void widgetDefaultSelected(SelectionEvent arg0) {
			}
		});
	}
	
	private void initFormItems() {
		scoreLabel = new Label(shell, SWT.NULL);
		scoreLabel.setText(" Score:");
		scoreLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		
		board = new Board(shell, SWT.BORDER);		
		board.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 18));
		board.addKeyListener(boardKeyListener);
		
		separatorLabel = new Label(shell, SWT.NULL);
		separatorLabel.setText("-----------------");
		separatorLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false, 1, 1));
		
		undoButton = new Button(shell, SWT.PUSH);
		undoButton.setText("Undo Move");
		undoButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		undoButton.addSelectionListener(undoSelected);
		
		restartButton = new Button(shell, SWT.PUSH);
		restartButton.setText("Restart Game");
		restartButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		restartButton.addSelectionListener(restartSelected);
		
		separatorLabel = new Label(shell, SWT.NULL);
		separatorLabel.setText("-----------------");
		separatorLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false, 1, 1));
		
		hintButton = new Button(shell, SWT.PUSH);
		hintButton.setText("Get Hint");
		hintButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		hintButton.addSelectionListener(hintSelected);
		
		hintImageLabel = new Label(shell, SWT.NULL);
		hintImageLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		
		separatorLabel = new Label(shell, SWT.NULL);
		separatorLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		
		separatorLabel = new Label(shell, SWT.NULL);
		separatorLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		
		separatorLabel = new Label(shell, SWT.NULL);
		separatorLabel.setText("-----------------");
		separatorLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false, 1, 1));

		stepsToSolveLabel = new Label(shell, SWT.NULL);
		stepsToSolveLabel.setText("Steps to solve:");
		stepsToSolveLabel.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false, 1, 1));
		
		stepsToSolveText = new Text(shell, SWT.BORDER);
		stepsToSolveText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		stepsToSolveText.addVerifyListener(numericalVerifier);
		
		solveButton = new Button(shell, SWT.PUSH);
		solveButton.setText("Auto Solve");
		solveButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
		solveButton.addSelectionListener(solveSelected);
	}
	
	public void init2048Game() {
		disposeObservers();
		
		model = new Game2048Model(settings.get2048BoardSize(), settings.get2048WinningTile());
    	view = new Game2048View(scoreLabel, board, settings.get2048BoardSize());
    	presenter = new Presenter(model, view);
    	
		((Game2048Model)model).addObserver(presenter);
		((Game2048View)view).addObserver(presenter);
	
    	model.initGame();
	}
	
	public void load2048Game(Stack<int[][]> moves, Stack<Integer> scores) {
		disposeObservers();
		
		model = new Game2048Model(settings.get2048BoardSize(), settings.get2048WinningTile(), moves, scores);
    	view = new Game2048View(scoreLabel, board, settings.get2048BoardSize());
    	presenter = new Presenter(model, view);
    	
		((Game2048Model)model).addObserver(presenter);
		((Game2048View)view).addObserver(presenter);

		model.undoMove();
	}
	
	public void initMazeGame(int[][] mazeMatrix) {
		disposeObservers();
		
		model = new GameMazeModel(mazeMatrix, settings.getStraightMoveScore(), settings.getDiagonalMoveScore());
    	view = new GameMazeView(board, mazeMatrix.length, mazeMatrix[0].length, scoreLabel);
    	presenter = new Presenter(model, view);
    	
		((GameMazeModel)model).addObserver(presenter);
		((GameMazeView)view).addObserver(presenter);

    	model.initGame();
	}
	
	public void loadMazeGame(Stack<int[][]> moves, Stack<Integer> scores) {
		disposeObservers();
		
		int[][] mazeMatrix = moves.peek();
		
		model = new GameMazeModel(moves, scores, settings.getStraightMoveScore(), settings.getDiagonalMoveScore());
    	view = new GameMazeView(board, mazeMatrix.length, mazeMatrix[0].length, scoreLabel);
    	presenter = new Presenter(model, view);
    	
		((GameMazeModel)model).addObserver(presenter);
		((GameMazeView)view).addObserver(presenter);
		
		model.undoMove();
	}
	
	private void disposeObservers() {
		if (model != null) {
			((Observable)model).deleteObservers();
		}
		
		if (view != null) {
			((Observable)view).deleteObservers();
		}
	}
	
	private boolean isGameInitialized(boolean checkLockedControls) {
		if (model == null || view == null ) {
			MessageBox messageBox = new MessageBox(shell);
			messageBox.setText("Start a new game");
			messageBox.setMessage("Please start a new game from the menu before using this option.");
			messageBox.open();
			
			return false;
		}
		else if (checkLockedControls && view.getLockControls()) {
			MessageBox messageBox = new MessageBox(shell);
			messageBox.setText("Restart the game");
			messageBox.setMessage("Please restart the game before using this option.");
			messageBox.open();
			
			return false;
		}
		
		return true;
	}
	
	SelectionAdapter newGame2048 = new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {		    	
	    	init2048Game();
	    }
	};
	
	SelectionAdapter starterGameMaze = new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {
	    	initMazeGame(settings.getStarterMaze());
	    }
	};
	
	SelectionAdapter easyGameMaze = new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {	
			MazeGenerator generator = new PrimMazeGenerator(settings.getEasyMazeWidth(), settings.getEasyMazeHeight());
			generator.generate();

	    	initMazeGame(generator.getGeneratedMaze());
	    }
	};
	
	SelectionAdapter mediumGameMaze = new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {	
			MazeGenerator generator = new HuntAndKillMazeGenerator(settings.getMediumMazeWidth(), settings.getMediumMazeHeight());
			generator.generate();
			
	    	initMazeGame(generator.getGeneratedMaze());
	    }
	};
	
	SelectionAdapter hardGameMaze = new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {
			MazeGenerator generator = new RecursiveBacktrackerMazeGenerator(settings.getHardMazeWidth(), settings.getHardMazeHeight());
			generator.generate();
			
	    	initMazeGame(generator.getGeneratedMaze());
	    }
	};

	SelectionListener loadSelected = new SelectionListener() {
		@Override
		public void widgetSelected(SelectionEvent arg0) {
			FileDialog dialog = new FileDialog(shell, SWT.OPEN);
			dialog.setFilterExtensions(new String[] { settings.getGameSettingsExtension() });
            String file = dialog.open();
            
            if (file != null) {
	            try {
					GameSettings settings = (GameSettings)XmlSerializer.loadSettings(file, new GameSettings());
					
					switch (settings.getGameName()) {
						case "2048":
							load2048Game(settings.getMoves(), settings.getScores());
							break;
						case "Maze":
							loadMazeGame(settings.getMoves(), settings.getScores());
							break;
						default:
							MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
							messageBox.setText("Error");
							messageBox.setMessage("Game is not supported!");
							messageBox.open();
							break;
					}
				}
	            catch (Exception e) {
	            	MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
					messageBox.setText("Error");
					messageBox.setMessage("There was a problem reading the file\n" + e.getMessage());
					messageBox.open();
				}
            }
            
            board.forceFocus();
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent arg0) {
		}
	};
	
	SelectionListener saveSelected = new SelectionListener() {
		@Override
		public void widgetSelected(SelectionEvent arg0) {
			if (isGameInitialized(true)) {
				FileDialog dialog = new FileDialog(shell, SWT.SAVE);
				dialog.setFilterExtensions(new String[] { settings.getGameSettingsExtension() });
	            String file = dialog.open();
	            
	            if (file != null) {
		            try {
		            	GameSettings settings = new GameSettings(model.getGameName(), model.getUndoMovesStack(), model.getUndoScoresStack());
						
		            	XmlSerializer.saveSettings(file, settings);
						
						MessageBox messageBox = new MessageBox(shell, SWT.ICON_INFORMATION | SWT.OK);
						messageBox.setText("Success");
						messageBox.setMessage("Game was saved successfuly.");
						messageBox.open();
					}
		            catch (Exception e) {
		            	MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
						messageBox.setText("Error");
						messageBox.setMessage("There was a problem saving the game\n" + e.getMessage());
						messageBox.open();
					}
	            }
			}
			
			board.forceFocus();
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent arg0) {
		}
	};
	
	SelectionAdapter exitSelected = new SelectionAdapter() {
	    @Override
	    public void widgetSelected(SelectionEvent e) {		    	
	    	shell.close();
	    }
	};
	
	VerifyListener numericalVerifier = new VerifyListener() {
		public void verifyText(VerifyEvent event) {
		    // Assume we don't allow it
			event.doit = false;
		 
		    // Get the character typed
		    char myChar = event.character;
		    
		    // Allow 0-9
		    if (Character.isDigit(myChar))
		    	event.doit = true;
		 
		    // Allow backspace
		    if (myChar == '\b')
		    	event.doit = true;
		}	  
	};
	
	SelectionListener undoSelected = new SelectionListener() {
		@Override
		public void widgetSelected(SelectionEvent arg0) {
			if (isGameInitialized(true)) {
				model.undoMove();
			}
			
			board.forceFocus();
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent arg0) {
		}
	};
	
	SelectionListener restartSelected = new SelectionListener() {
		@Override
		public void widgetSelected(SelectionEvent arg0) {
			if (isGameInitialized(false)) {
				model.initGame();
			}
			
			board.forceFocus();
		}
		
		@Override
		public void widgetDefaultSelected(SelectionEvent arg0) {
		}
	};
	
	KeyListener boardKeyListener = new KeyListener() {
		@Override
		public void keyReleased(KeyEvent arg0) {
		}
		
		@Override
		public void keyPressed(KeyEvent arg0) {
		}
	};
	
	private Timer timer = new Timer();
	private TimerTask task;
	SelectionListener hintSelected = new SelectionListener() {
		@Override
		public void widgetSelected(SelectionEvent arg0) {
			if (isGameInitialized(true)) {
				try {
					if (task != null) {
						task.cancel();
					}
					
					hintImageLabel.setSize(50, 50);
					
					if (hintImage != null) {
						hintImage.dispose();
					}
					
					int hint = ServerHandler.getHint(model.getGameName(), model.getBoard(), model.getScore());
						
					switch (hint) {
						case 1: {
							hintImage = new Image(display, settings.getHintImageUp());
							break;
						}
						case 2: {
							hintImage = new Image(display, settings.getHintImageDown());
							break;
						}
						case 3: {
							hintImage = new Image(display, settings.getHintImageLeft());
							break;
						}
						case 4: {
							hintImage = new Image(display, settings.getHintImageRight());
							break;
						}
						case 5: {
							hintImage = new Image(display, settings.getHintImageUpRight());
							break;
						}
						case 6: {
							hintImage = new Image(display, settings.getHintImageUpLeft());
							break;
						}
						case 7: {
							hintImage = new Image(display, settings.getHintImageDownRight());
							break;
						}
						case 8: {
							hintImage = new Image(display, settings.getHintImageDownLeft());
							break;	
						}
						default:
							break;
					};
					
					if (hintImage != null) {
						hintImageLabel.setImage(hintImage);
					}
					
					task = new WrapperTask(new Runnable() {
						@Override
						public void run() {
							board.getDisplay().syncExec(new Runnable() {
								@Override
								public void run() {
									hintImageLabel.setImage(null);
								}
							});
						}
					});
					
				    timer.schedule(task, settings.getHintTimeout()); 
				}
				catch (Exception e) {
					MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
					messageBox.setText("Error");
					messageBox.setMessage("There was a problem with the connection\n" + e.getMessage());
					messageBox.open();
				}	
			}
					
			board.forceFocus();
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent arg0) {
		}
	};
	
	private Thread solver;
	private int numOfSteps;
	SelectionListener solveSelected = new SelectionListener() {
		@Override
		public void widgetSelected(SelectionEvent arg0) {
			if (isGameInitialized(true)) {
				try {
					if (solver != null && solver.isAlive()) {
						solveButton.setText("Auto Solve");
						
						solver.interrupt();
					}
					else {
						if (stepsToSolveText.getText().isEmpty()) {
							numOfSteps = 0;
						}
						else {
							numOfSteps = Integer.parseInt(stepsToSolveText.getText());
						}
						
						solver = new Thread(autoSolve);
						solver.start();
						
						solveButton.setText("Stop");
					}
				}
				catch (Exception e) {
					MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
					messageBox.setText("Error");
					messageBox.setMessage("There was a problem with the connection\n" + e.getMessage());
					messageBox.open();
				}
			}
					
			board.forceFocus();
		}

		@Override
		public void widgetDefaultSelected(SelectionEvent arg0) {
		}
	};

	Runnable autoSolve = new Runnable() {
	    @Override
	    public void run() {
			try {
				switch (model.getGameName()) {
					case "Maze":
						ArrayList<Integer> solution = ServerHandler.getSolution(model.getGameName(), model.getBoard(), model.getScore());
						
						if (numOfSteps == 0) {
							for (Integer step : solution) {
								solve(step);
							}
						}
						else {
							int actualCount = Math.min(numOfSteps, solution.size());
							
							for (int i = 0; i < actualCount; i++) {
								solve(solution.get(i));
							}	
						}
						break;
					case "2048":
						if (numOfSteps == 0) {
							while (model.getGameState() == 0) {
								solve(ServerHandler.getSolution(model.getGameName(), model.getBoard(), model.getScore()).get(0));
							}
						}
						else {
							for (int i = 0; i < numOfSteps; i++) {
								int step = ServerHandler.getSolution(model.getGameName(), model.getBoard(), model.getScore()).get(0);
								
								solve(step);
								
								if (step == 0)
									break;
							}	
						}
						break;
					default:
						break;
				}
			}
			catch (InterruptedException e) {
				System.out.println("Auto solution interrupted");
			}
			catch (IOException | ClassNotFoundException  e) {
				board.getDisplay().syncExec(new Runnable() {
					@Override
					public void run() {
						MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
						messageBox.setText("Error");
						messageBox.setMessage("There was a problem with the connection\n" + e.getMessage());
						messageBox.open();
					}
				});
			}
			finally {
				board.getDisplay().syncExec(new Runnable() {
					@Override
					public void run() {
						solveButton.setText("Auto Solve");
					}
				});
			}
	    }
	};
	
	private void solve(int step) throws InterruptedException {	
		switch (step) {
			case 0:
				// Make one more fictive move to end the game
				model.moveUp();
				break;
			case 1:
				model.moveUp();
				break;
			case 2:
				model.moveDown();
				break;
			case 3:
				model.moveLeft();
				break;
			case 4:
				model.moveRight();
				break;
			case 5:
				model.moveUpRight();
				break;
			case 6:
				model.moveUpLeft();
				break;
			case 7:
				model.moveDownRight();
				break;
			case 8:
				model.moveDownLeft();
				break;
			default:
				break;
		}
		
		Thread.sleep(autoSolveSpeed);
	}
}